﻿/*
 * SRSTransform
 * 
 * initial implementation : 20.11.2008
 *
 * Copyright (c) Adam Sida, asida@centrum.cz.
 * All rights reserved.
 * 
 * for license see Petra.Gis.License.txt
 */
using System;
using System.Collections.Generic;
using Petra.Gis.Geometry;
using Petra.Gis.Geometry.Support;
using Petra.Gis.ReferenceSystemServices;


namespace Petra.Gis.ReferenceSystemServices.Transformations
{
  public abstract partial class SRSTransform
  {

    /// <summary>
    /// Transforms a <see cref="Petra.Gis.Geometry.Support.BoundingBox"/>.
    /// </summary>
    /// <param name="box">BoundingBox to transform</param>
    /// <returns>Transformed object</returns>
    public BoundingBox TransformBox(BoundingBox box)
    {
      if (box == null)
        return null;
      CoordinateList corners = new CoordinateList(4, Dimension.dim3D);
      corners[0] = this.Transform(box.Min); //LL
      corners[1] = this.Transform(box.Max); //UR
      corners[2] = this.Transform(new CoordStruct(box.Min.X, box.Max.Y)); //UL
      corners[3] = this.Transform(new CoordStruct(box.Max.X, box.Min.Y)); //LR

      return corners.getEnvelope();
    }




    /// <summary>
    /// Transforms a <see cref="Petra.Gis.Geometry.GeometryBase"/>.
    /// </summary>
    /// <param name="g">Geometry to transform</param>
    /// <returns>Transformed object</returns>
    public GeometryBase Transform(GeometryBase g)
    {
      if (g == null)
        return null;
      else if (g is Point)
        return TransformPoint(g as Point);
      else if (g is LineString)
        return TransformLineString(g as LineString);
      else if (g is Polygon)
        return TransformPolygon(g as Polygon);
      else if (g is MultiPoint)
        return TransformMultiPoint(g as MultiPoint);
      else if (g is MultiLine)
        return TransformMultiLine(g as MultiLine);
      else if (g is MultiArea)
        return TransformMultiPolygon(g as MultiArea);
      else if (g is Grid)
        return TransformGrid(g as Grid);
      else
        throw new ArgumentException("Could not transform geometry type '" + g.GetType().ToString() + "'");
    }




    /// <summary>
    /// Transforms a <see cref="Petra.Gis.Geometry.Point"/>.
    /// </summary>
    /// <param name="p">Point to transform</param>
    /// <returns>Transformed object</returns>
    public Point TransformPoint(Point p)
    {
      this.Transform(p.coordList);
      return p;
    }



    /// <summary>
    /// Transforms a <see cref="Petra.Gis.Geometry.LineString"/>.
    /// </summary>
    /// <param name="l">LineString to transform</param>
    /// <returns>Transformed object</returns>
    public LineString TransformLineString(LineString l)
    {
      this.Transform(l.coordList);
      return l;
    }




    /// <summary>
    /// Transforms a <see cref="Petra.Gis.Geometry.LinearRing"/>.
    /// </summary>
    /// <param name="r">LinearRing to transform</param>
    /// <returns>Transformed object</returns>
    public LineRing TransformLinearRing(LineRing r)
    {
      this.Transform(r.coordList);
      return r;
    }




    /// <summary>
    /// Transforms a <see cref="Petra.Gis.Geometry.Polygon"/>.
    /// </summary>
    /// <param name="p">Polygon to transform</param>
    /// <returns>Transformed object</returns> 
    public Polygon TransformPolygon(Polygon p)
    {
      foreach(LineRing r in p)
        TransformLinearRing(r);

      return p;

    }




    /// <summary>
    /// Transforms a <see cref="Petra.Gis.Geometry.MultiPoint"/>.
    /// </summary>
    /// <param name="points">MultiPoint to transform</param>
    /// <returns>Transformed object</returns>
    public MultiPoint TransformMultiPoint(MultiPoint points)
    {
      foreach (Point p in points)
        this.Transform(p.coordList);

      return points;
    }




    /// <summary>
    /// Transforms a <see cref="Petra.Gis.Geometry.MultiLineString"/>.
    /// </summary>
    /// <param name="lines">MultiLineString to transform</param>
    /// <returns>Transformed object</returns>
    public MultiLine TransformMultiLine(MultiLine lines)
    {
      foreach (LineString l in lines)
        this.Transform(l.coordList);

      return lines;
    }




    /// <summary>
    /// Transforms a <see cref="Petra.Gis.Geometry.MultiPolygon"/>.
    /// </summary>
    /// <param name="polys">MultiPolygon to transform</param>
    /// <returns>Transformed object</returns>
    public MultiArea TransformMultiPolygon(MultiArea polys)
    {

      foreach (Polygon p in polys)
        this.TransformPolygon(p);

      return polys;
    }




    /// <summary>
    /// Transforms a <see cref="Petra.Gis.Geometry.GeometryCollection"/>.
    /// </summary>
    /// <param name="geoms">GeometryCollection to transform</param>
    /// <returns>Transformed object</returns>
    public void TransformGeometryCollection(GeometryCollection geoms)
    {
      foreach (GeometryBase g in geoms)
        this.Transform(g);
    }




    /// <summary>
    /// TransformGrid is only void function
    /// grid is transformed during rendering process
    /// where transform is optimized for best performance
    /// </summary>
    /// <param name="geom">input geometry</param>
    /// <returns>unchanged input geometry</returns>
    public Grid TransformGrid(Grid geom)
    {
      return geom;
    }


    //todo: more....

  }
}
